package com.itheima.controller;

import com.itheima.bean.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CacheController {

    // springCache是对具体的缓存实现做向上抽象， 它使用一个管理员来对接这些具体的实现
    // springCache认为所有的缓存功能，应该由一个管理员来实现它。
    // 这个管理员由具体的实现类来提供。 redis--- redisCacheManager

    /*
        之所以注入进来CacheManager ，目的就是为了告诉大家缓存数据到底用的是谁？
        可以使用debug来查看到数据到底有没有被缓存，缓存了多少？
     */
    @Autowired
    private CacheManager cacheManager;


    /**
     * @CachePut注解使用：
     *  1. 把方法的返回值放到缓存里面去！
     *  2. 解释属性：
     *      cacheNames: 表示缓存的这一种大类的数据标识，比如缓存用户的数据，那么cacheNames ： user , 比如缓存学生的数据， 那么cacheNames ： stu ...
     *      key： 表示具体缓存的这一条数据。不可以是一个固定值，否则缓存很多条数据，最终会发现只有一条！
     *          它必须动态变化... 就需要根据方法参数或者方法的返回值来作为缓存的key
     *          #result: 表示可以得到方法的返回值 ， 如果返回值是一个的对象，获取内部的属性：#result.属性
     *          #root.args[0] | #p0 | #a0 ： 表示可以获取到第1个参数。
     *          #root.args[1] | #p1 | #a1 ： 表示可以获取到第2个参数。
     * @return
     */
    //TODO:: 在这里写进来CachePut注解，然后debug运行程序，观察上面的cacheManager 的内容
    @CachePut(cacheNames = "user" , key = "#result.id")
    @RequestMapping("/add")
    public User addUser( int id , String name , int age){
        System.out.println("--------add--------------");
        return new User(id , name , age);
    }


    /**
     * 根据ID来查询用户
     * @Cacheable:
     *      特征：
     *          1. 先去执行缓存的查询，如果有就直接返回【方法根本不会执行】
     *          2. 如果缓存没有，那么就会执行方法，并且把方法的返回值放到缓存中
     *      cacheNames: 查询哪一种大类里面的缓存数据
     *      key: 查询具体的哪一个缓存数据。\
     *
     *  细节处理：
     *      1. 空值的处理...
     *      2. 不要把空值存储到缓存当中！
     *      3. 使用两个属性来解决这个问题
     *          condition: 满足这样的条件 ，然后就存储 它不能取到返回值...
     *          unless: 不满足这样的条件，然后就缓存
     *
     *
     *
     * @param id
     * @return
     */
    //@Cacheable(cacheNames = "user" , key = "#p0" , condition = "结果不为空，就缓存" , unless = "结果为空，否则就缓存")
    //@Cacheable(cacheNames = "user" , key = "#p0" )
    @Cacheable(cacheNames = "user" , key = "#p0", unless = "#result == null")
    @RequestMapping("/findById")
    public User findById(int id){ // 9999999999999999
        System.out.println("findById............");

        if(id == 0){
            return null;
        }

        //1. 先去缓存里面查，有就直接返回
        //2. 如果没有就去查询数据库
        //3. 查询到了之后还要添加到缓存中。
        return new User(id,"无名氏", 18);
    }


    /**
     * @CacheEvict:
     *  作用： 用来删除一条或者多条缓存数据
     *  属性：
     *      cacheNames： 删除哪个大类
     *      key ： 大类中的哪一个具体的数据，给定唯一的标识。
     *
     * @param id
     * @return
     */
    @CacheEvict(cacheNames = "user" , key = "#id")
    @RequestMapping("/delete")
    public String delete(int id){
        System.out.println("删除..." + id);
        return "删除成功了~！";
    }

    /**
     * 删除user这一大类的数据
     * @return
     */
    @CacheEvict(cacheNames = "user", allEntries = true)
    @RequestMapping("/deleteAll")
    public String deleteAll(){
        System.out.println("删除User类的所有缓存数据...");
        return "删除成功了~！";
    }


}
